package decrypt.utils;

import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

/**
 * A wrapper for some Decryption methods.
 * 
 * 
 */
public class Dec
{
    /**
     * Get SecretKey from raw bytes of AES key
     * 
     * @param aesKey
     * @return
     */
    public static SecretKey getAESKey( byte[] aesKey ) {
        return new SecretKeySpec( aesKey, "AES" );
    }

    /**
     * Get PrivateKey from raw bytes of pkcs8 encoded key
     * 
     * @param c_pkcs8
     * @return
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeySpecException
     */
    public static PrivateKey getPrivateKeyFromRawBytes( byte[] c_pkcs8 )
            throws NoSuchAlgorithmException, InvalidKeySpecException {
        KeyFactory keyFactory = KeyFactory.getInstance( "RSA" );

        PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec( c_pkcs8 );
        PrivateKey privateKey = keyFactory.generatePrivate( privateKeySpec );
        return privateKey;
    }

    /**
     * Decrypt RSA, OAEPwithSHA256andMGF1 padding.
     * 
     * @param c_rsa_oaepwithsha256andmgf1
     *            cipher text
     * @param k
     *            private key of rsa
     * @return raw bytes of plain text
     * @throws InvalidKeyException
     */
    public static byte[] decRsaOAEP( byte[] c_rsa_oaepwithsha256andmgf1,
            PrivateKey k ) throws InvalidKeyException {
        Cipher dec = null;
        try {
            dec = Cipher.getInstance( "RSA/ECB/OAEPWITHSHA-256ANDMGF1PADDING" );
        } catch( NoSuchAlgorithmException e ) {
            e.printStackTrace();
        } catch( NoSuchPaddingException e ) {
            e.printStackTrace();
        }

        dec.init( Cipher.DECRYPT_MODE, k );

        byte[] result = null;
        try {
            result = dec.doFinal( c_rsa_oaepwithsha256andmgf1 );
        } catch( IllegalBlockSizeException e ) {
            e.printStackTrace();
        } catch( BadPaddingException e ) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * Decrypt AES in CBC mode with pkcs5 padding.
     * 
     * @param c_aes_cbc
     *            cipher text
     * @param aesKey
     *            AES Secret Key
     * @param iv
     *            Initialize vector
     * @return plain text
     * @throws InvalidKeyException
     * @throws InvalidAlgorithmParameterException
     */
    public static byte[] decAESCBC( byte[] c_aes_cbc, SecretKey aesKey,
            byte[] iv ) throws InvalidKeyException,
            InvalidAlgorithmParameterException {
        Cipher dec = null;
        try {
            dec = Cipher.getInstance( "AES/CBC/PKCS5PADDING" );
        } catch( NoSuchAlgorithmException e ) {
            e.printStackTrace();
        } catch( NoSuchPaddingException e ) {
            e.printStackTrace();
        }

        dec.init( Cipher.DECRYPT_MODE, aesKey, new IvParameterSpec( iv ) );
        byte[] result = null;
        try {
            result = dec.doFinal( c_aes_cbc );
        } catch( IllegalBlockSizeException e ) {
            e.printStackTrace();
        } catch( BadPaddingException e ) {
            e.printStackTrace();
        }
        return result;
    }
}
